import tkinter as tk
from tkinter import ttk, messagebox
import json
import os
import keyboard
import pyperclip
from typing import Dict, Optional

class HotkeyConfigPanel:
    """单个快捷键配置面板"""
    def __init__(self, parent: tk.Frame, index: int):
        self.frame = tk.Frame(parent)
        self.frame.pack(side=tk.TOP, fill=tk.X, pady=5)
        self.index = index
        self.current_prompt: Optional[Dict] = None
        
        self.setup_ui()
        
    def setup_ui(self):
        """设置UI组件"""
        # 快捷键配置区
        hotkey_label = tk.Label(self.frame, text=f"快捷键 {self.index}:", width=10)
        hotkey_label.pack(side=tk.LEFT, padx=5)
        
        self.hotkey_entry = tk.Entry(self.frame, width=15)
        self.hotkey_entry.pack(side=tk.LEFT, padx=5)
        
        # 应用按钮
        self.apply_button = tk.Button(
            self.frame,
            text=f"应用到高频快捷键{self.index}",
            state=tk.DISABLED
        )
        self.apply_button.pack(side=tk.LEFT, padx=5)
        
        # 结果显示
        self.result_label = tk.Label(
            self.frame, 
            text="当前未配置",
            wraplength=300,  # 添加自动换行
            anchor='w',
            justify='left'  # 左对齐
        )
        self.result_label.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)  # 允许扩展
        self.result_label.pack(side=tk.LEFT, padx=5)
        
    def set_callback(self, callback):
        """设置应用按钮的回调函数"""
        self.apply_button.config(command=lambda: callback(self))
        
    def enable(self):
        """启用应用按钮"""
        self.apply_button.config(state=tk.NORMAL)
        
    def disable(self):
        """禁用应用按钮"""
        self.apply_button.config(state=tk.DISABLED)
        
    def get_config(self) -> Dict:
        """获取当前配置"""
        return {
            'hotkey': self.hotkey_entry.get().strip(),
            'prompt': self.current_prompt
        }
        
    def set_config(self, config: Dict):
        """设置配置"""
        self.hotkey_entry.delete(0, tk.END)
        self.hotkey_entry.insert(0, config.get('hotkey', ''))
        self.current_prompt = config.get('prompt')
        if self.current_prompt:
            self.result_label.config(text=f"已绑定: {self.current_prompt.get('name', '未命名')}")
        else:
            self.result_label.config(text="当前未配置")

class HighFreqHotkeyWindow:
    # 添加类变量跟踪窗口实例
    _instance = None
    
    def __new__(cls, parent, data_manager):
        if cls._instance is not None and cls._instance.window.winfo_exists():
            cls._instance.window.focus_force()  # 将已存在的窗口置于前台
            cls._instance.window.lift()  # 确保窗口在最上层
            return None
        return super().__new__(cls)
    
    def __init__(self, parent, data_manager):
        # 如果是重复创建实例，直接返回
        if hasattr(self, 'window'):
            return
            
        self.window = tk.Toplevel(parent)
        self.window.title("高频快捷键管理")
        
        # 保存实例引用
        self.__class__._instance = self
        
        # 绑定窗口关闭事件
        self.window.protocol("WM_DELETE_WINDOW", self._on_closing)
        
        # 加载配置
        self.config = self.load_config()
        
        # 设置窗口大小
        window_width = self.config.get('high_freq_window_width', 1200)  # 默认宽度
        window_height = 600  # 固定高度
        
        # 获取屏幕尺寸
        screen_width = self.window.winfo_screenwidth()
        screen_height = self.window.winfo_screenheight()
        
        # 计算窗口位置
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        
        # 设置窗口大小和位置
        self.window.geometry(f"{window_width}x{window_height}+{x}+{y}")
        
        # 允许调整窗口大小
        self.window.resizable(True, True)
        
        # 绑定窗口大小改变事件
        self.window.bind('<Configure>', self.on_window_resize)
        
        # 设置最小窗口大小
        self.window.minsize(1000, 600)  # 增加最小宽度
        
        self.data_manager = data_manager
        
        # 绑定右键双击事件到窗口
        self.window.bind('<Double-Button-3>', lambda e: self.window.destroy())
        
        # 当前选中的提示词数据
        self.current_prompt = None
        
        # 快捷键配置管理器
        self.hotkey_configs = {}
        
        # 确保配置目录存在
        # 修改前：self.config_dir = os.path.join('high_frequency_hotkey')
        # 修改后：直接使用根目录下的 configs_all
        self.config_dir = 'configs_all'
        if not os.path.exists(self.config_dir):
            os.makedirs(self.config_dir)
            
        # 修改初始化顺序
        self.setup_ui()  # 先创建UI
        self.load_hotkey_configs()  # 然后加载快捷键配置
        self.load_data()  # 最后加载数据

    def setup_ui(self):
        """设置UI界面"""
        # 添加红色加粗提示语句
        tip_frame = ttk.Frame(self.window)
        tip_frame.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)
        tip_frame.bind('<Double-Button-3>', lambda e: self.window.destroy())
        
        tip_label = ttk.Label(tip_frame, 
                             text="鼠标右键双击任意位置关闭本窗口", 
                             font=('Arial', 10, 'bold'),
                             foreground='red')
        tip_label.pack(pady=5)
        tip_label.bind('<Double-Button-3>', lambda e: self.window.destroy())
        
        # 添加清空提示词按钮
        clear_button = tk.Button(tip_frame, text="清空提示词", command=self.clear_hotkey_configs)
        clear_button.pack(side=tk.RIGHT, padx=5)
        
        # 为每个创建的组件添加右键双击事件
        def add_right_click_binding(widget):
            widget.bind('<Double-Button-3>', lambda e: self.window.destroy())
            # 如果是容器类组件,为其子组件也添加绑定
            if isinstance(widget, (tk.Frame, ttk.Frame)):
                for child in widget.winfo_children():
                    add_right_click_binding(child)
        
        # 修改UI创建顺序
        self.create_search_frame()
        self.create_list_frame()  # 这个方法现在包含了所有UI创建
        
        # 为所有已创建的组件添加右键双击事件
        add_right_click_binding(self.window)

    def create_search_frame(self):
        """创建搜索框架"""
        search_frame = tk.Frame(self.window)
        search_frame.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)
        search_frame.bind('<Double-Button-3>', lambda e: self.window.destroy())
        
        # 全局搜索
        global_search_label = tk.Label(search_frame, text="全局搜索:")
        global_search_label.pack(side=tk.LEFT)
        
        self.global_search_entry = tk.Entry(search_frame)
        self.global_search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(5, 20))
        self.global_search_entry.bind('<KeyRelease>', self.on_global_search)
        
        # 分组搜索
        group_search_label = tk.Label(search_frame, text="当前分组搜索:")
        group_search_label.pack(side=tk.LEFT)
        
        self.group_search_entry = tk.Entry(search_frame)
        self.group_search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        self.group_search_entry.bind('<KeyRelease>', self.on_group_search)

    def on_global_search(self, event):
        """处理全局搜索"""
        keyword = self.global_search_entry.get().strip()
        # 清除分组搜索的内容，避免冲突
        self.group_search_entry.delete(0, tk.END)
        
        if not keyword:
            self.refresh_lists()  # 清空搜索时恢复原始显示
            return
            
        # 清空当前列表
        self.group_list.delete(0, tk.END)
        self.file_list.delete(0, tk.END)
        
        # 执行搜索
        for file in self.data_manager.get_all_files():
            try:
                with open(self.data_manager.get_data_path(file), 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    # 搜索所有字段
                    if self._search_in_data(keyword, data):
                        group = data.get('group', '')
                        if group not in [self.group_list.get(i) for i in range(self.group_list.size())]:
                            self.group_list.insert(tk.END, group)
                        self.file_list.insert(tk.END, file)
            except Exception as e:
                print(f"搜索文件出错: {file}, {str(e)}")

    def on_group_search(self, event):
        """处理分组搜索"""
        if not self.group_list.curselection():
            return
            
        keyword = self.group_search_entry.get().strip()
        # 清除全局搜索的内容，避免冲突
        self.global_search_entry.delete(0, tk.END)
        
        group = self.group_list.get(self.group_list.curselection())
        
        if not keyword:
            self.load_files_from_group(None)  # 清空搜索时恢复原始显示
            return
            
        # 清空文件列表
        self.file_list.delete(0, tk.END)
        
        # 执行搜索
        for file in self.data_manager.get_files_by_group(group):
            try:
                with open(self.data_manager.get_data_path(file), 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    if self._search_in_data(keyword, data):
                        self.file_list.insert(tk.END, file)
            except Exception as e:
                print(f"搜索文件出错: {file}, {str(e)}")

    def _search_in_data(self, keyword: str, data: Dict) -> bool:
        """在数据中搜索关键词"""
        keyword = keyword.lower()
        # 搜索所有文本字段
        for field in ['name', 'content', 'comment', 'group']:
            if keyword in str(data.get(field, '')).lower():
                return True
        return False

    def refresh_lists(self):
        """刷新列表"""
        # 刷新分组列表
        self.group_list.delete(0, tk.END)
        groups = self.data_manager.get_all_groups()
        for group in groups:
            self.group_list.insert(tk.END, group)

    def create_list_frame(self):
        """创建左侧列表框架"""
        # 创建主水平分割框架
        main_frame = tk.Frame(self.window)
        main_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        
        # 左侧列表框架
        list_frame = tk.Frame(main_frame)
        list_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(5,0))  # 只在左侧加padding
        list_frame.bind('<Double-Button-3>', lambda e: self.window.destroy())
        
        # 分组列表
        self.group_list = tk.Listbox(list_frame, width=20, font=('Arial', 12))
        self.group_list.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.group_list.bind('<<ListboxSelect>>', self.load_files_from_group)

        # 文件列表
        self.file_list = tk.Listbox(list_frame, width=30, font=('Arial', 12))
        self.file_list.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.file_list.bind('<<ListboxSelect>>', self.load_file)
        
        # 右侧内容区域（包含提示词信息和快捷键配置）
        right_frame = tk.Frame(main_frame)
        right_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5)
        
        # 提示词信息区域
        content_frame = tk.Frame(right_frame)
        content_frame.pack(side=tk.TOP, fill=tk.X, expand=False)
        content_frame.bind('<Double-Button-3>', lambda e: self.window.destroy())
        
        # 提示词名称文本框
        self.prompt_name_label = tk.Label(content_frame, text="提示词名称:", font=('Arial', 14))
        self.prompt_name_label.pack(pady=(0,2))  # 减小顶部间距
        self.prompt_name_text = tk.Text(content_frame, height=1, width=50, font=('Arial', 14))
        self.prompt_name_text.pack(fill=tk.X, pady=(0,5))  # 减小间距

        # 提示词内容文本框
        self.prompt_content_label = tk.Label(content_frame, text="提示词内容:", font=('Arial', 14))
        self.prompt_content_label.pack(pady=(0,2))  # 减小间距
        self.prompt_content_text = tk.Text(content_frame, height=8, width=50, font=('Arial', 14))
        self.prompt_content_text.pack(fill=tk.X, pady=(0,5))  # 减小间距
        
        # 快捷键配置区域
        self.create_hotkey_frame(right_frame)  # 传入right_frame作为父容器

    def create_content_frame(self):
        """此方法不再需要，内容已移至create_list_frame中"""
        pass

    def create_hotkey_frame(self, parent_frame):
        """创建快捷键配置区域"""
        # 创建一个Frame来容纳滚动条和内容
        outer_frame = tk.Frame(parent_frame)
        outer_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True, pady=(0,5))  # 减小顶部间距
        
        # 创建Canvas和Scrollbar
        canvas = tk.Canvas(outer_frame)
        scrollbar = ttk.Scrollbar(outer_frame, orient="vertical", command=canvas.yview)
        
        # 创建内部Frame来放置所有配置面板
        self.hotkey_frame = tk.Frame(canvas)
        
        # 配置Canvascanvas.configure(yscrollcommand=scrollbar.set)
        canvas.configure(yscrollcommand=scrollbar.set)
        
        # 打包滚动条和Canvas
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        # 在Canvas中创建窗口来显示内部Frame
        canvas.create_window((0, 0), window=self.hotkey_frame, anchor="nw")
        
        # 创建15个配置面板
        self.config_panels = []
        for i in range(15):
            panel = HotkeyConfigPanel(self.hotkey_frame, i + 1)
            panel.set_callback(self.apply_hotkey)
            self.config_panels.append(panel)
        
        # 绑定鼠标滚轮事件
        def _on_mousewheel(event):
            canvas.yview_scroll(int(-1*(event.delta/100)), "units")
        canvas.bind_all("<MouseWheel>", _on_mousewheel)
        
        # 更新Canvas的滚动区域
        def _configure_canvas(event):
            canvas.configure(scrollregion=canvas.bbox("all"))
        self.hotkey_frame.bind('<Configure>', _configure_canvas)

    def load_file(self, event):
        """加载选中的文件内容"""
        if not self.file_list.curselection():
            return
            
        selected_file = self.file_list.get(self.file_list.curselection())
        file_path = self.data_manager.get_data_path(selected_file)
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
                self.current_prompt = data
                
                self.prompt_name_text.delete(1.0, tk.END)
                self.prompt_name_text.insert(tk.END, selected_file)
                self.prompt_content_text.delete(1.0, tk.END)
                self.prompt_content_text.insert(tk.END, data.get('content', ''))
                
                # 启用所有配置面板
                for panel in self.config_panels:
                    panel.enable()
                    panel.current_prompt = data
                    
        except Exception as e:
            messagebox.showerror("错误", f"加载文件失败: {str(e)}")

    def apply_hotkey(self, panel: HotkeyConfigPanel):
        """应用快捷键配置"""
        if not panel.current_prompt:
            return
            
        hotkey = panel.hotkey_entry.get().strip()
        if not hotkey:
            messagebox.showwarning("警告", "请输入快捷键", parent=self.window)
            return
            
        try:
            # 如果该位置已有快捷键，先解除绑定
            if panel.index in self.hotkey_configs:
                old_config = self.hotkey_configs[panel.index]
                keyboard.remove_hotkey(old_config['handle'])  # 使用句柄移除旧热键
                
            # 获取文件名
            filename = self.prompt_name_text.get("1.0", "end-1c").strip()
            
            # 注册新快捷键（使用闭包实时捕获文件名）
            def create_callback(fname):
                def callback():
                    try:
                        file_path = self.data_manager.get_data_path(fname)
                        with open(file_path, 'r', encoding='utf-8') as f:
                            data = json.load(f)
                            pyperclip.copy(data.get('content', ''))
                    except Exception as e:
                        print(f"读取prompt内容失败: {str(e)}")
                return callback
            def create_callback(fname):
                def callback():
                    try:
                        file_path = self.data_manager.get_data_path(fname)
                        with open(file_path, 'r', encoding='utf-8') as f:
                            data = json.load(f)
                            pyperclip.copy(data.get('content', ''))
                    except Exception as e:
                        print(f"读取prompt内容失败: {str(e)}")
                return callback
            handle = keyboard.add_hotkey(hotkey, create_callback(filename))
            self.hotkey_configs[panel.index] = {
                'hotkey': hotkey,
                'filename': filename,
                'handle': handle  # 存储热键句柄
            }
            
            # 更新显示
            panel.result_label.config(
                text=f"已绑定: {filename}"
            )
            
            # 1
            # 保存配置到文件
            self.save_hotkey_configs()
            
            messagebox.showinfo("成功", f"快捷键 {hotkey} 配置成功", parent=self.window)
            
        except Exception as e:
            messagebox.showerror("错误", f"配置快捷键失败: {str(e)}", parent=self.window)

    def load_hotkey_configs(self):
        """加载快捷键配置"""
        try:
            config_path = os.path.join(self.config_dir, 'hotkey_configs.json')
            if not os.path.exists(config_path):
                return
                
            # 添加文件内容空检查
            if os.path.getsize(config_path) == 0:
                print("配置文件为空，跳过加载")
                return
                
            with open(config_path, 'r', encoding='utf-8') as f:
                # 添加try-except处理无效JSON内容
                try:
                    self.hotkey_configs = json.load(f)
                except json.JSONDecodeError:
                    print("配置文件格式错误，跳过加载")
                    return
                    
            # 恢复配置显示和注册快捷键...
            for index_str, config in self.hotkey_configs.items():
                try:
                    index = int(index_str)
                    if 0 <= index - 1 < len(self.config_panels):
                        panel = self.config_panels[index - 1]
                        
                        # 设置显示
                        hotkey = config.get('hotkey', '')
                        filename = config.get('filename', '')
                        
                        # 清空并设置快捷键
                        panel.hotkey_entry.delete(0, tk.END)
                        panel.hotkey_entry.insert(0, hotkey)
                        
                        # 更新显示文本
                        panel.result_label.config(text=f"已绑定: {filename}")
                        
                        # 尝试加载对应的提示词数据
                        try:
                            file_path = self.data_manager.get_data_path(filename)
                            # 添加文件存在性检查
                            if not os.path.exists(file_path):
                                panel.result_label.config(text=f"文件不存在: {filename}")
                                continue  # 跳过不存在的文件
                                
                            if os.path.exists(file_path):
                                with open(file_path, 'r', encoding='utf-8') as f:
                                    data = json.load(f)
                                    panel.current_prompt = data
                                    panel.enable()  # 启用面板
                                    
                                # 注册快捷键
                                def create_copy_function(filename):
                                    def copy_content():
                                        try:
                                            file_path = self.data_manager.get_data_path(filename)
                                            # 再次检查文件存在性
                                            if not os.path.exists(file_path):
                                                print(f"文件不存在: {filename}")
                                                return
                                            with open(file_path, 'r', encoding='utf-8') as f:
                                                data = json.load(f)
                                                content = data.get('content', '')
                                                pyperclip.copy(content)
                                        except Exception as e:
                                            print(f"读取prompt内容失败: {str(e)}")
                                    return copy_content
                                
                                keyboard.add_hotkey(hotkey, create_copy_function(filename))
                        except Exception as e:
                            print(f"加载提示词数据失败: {filename}, {str(e)}")
                            panel.result_label.config(text=f"加载失败: {filename}")
                            
                except Exception as e:
                    print(f"处理快捷键配置失败: index={index_str}, {str(e)}")
                    continue
                    
        except Exception as e:
            # 移除会阻塞的messagebox提示
            print(f"加载快捷键配置失败（已跳过）: {str(e)}")  # 修改为仅打印错误
            messagebox.showerror("错误", f"加载快捷键配置失败: {str(e)}", parent=self.window)

    def save_hotkey_configs(self):
        """保存快捷键配置"""
        try:
            config_path = os.path.join(self.config_dir, 'hotkey_configs.json')
            # 移除不可序列化的handle字段
            sanitized_config = {
                k: {'hotkey': v['hotkey'], 'filename': v['filename']} 
                for k, v in self.hotkey_configs.items()
            }
            with open(config_path, 'w', encoding='utf-8') as f:
                json.dump(sanitized_config, f, ensure_ascii=False, indent=4)
        except Exception as e:
            messagebox.showerror("错误", f"保存快捷键配置失败: {str(e)}")

    def load_data(self):
        """初始化数据"""
        try:
            # 加载分组列表
            groups = self.data_manager.get_all_groups()
            self.group_list.delete(0, tk.END)  # 清空现有内容
            for group in groups:
                self.group_list.insert(tk.END, group)
                
            # 如果有分组，默认选中第一个分组并加载其文件
            if groups:
                self.group_list.select_set(0)
                self.load_files_from_group(None)  # None 表示不是由事件触发
                
                # 如果有文件，默认选中第一个文件并加载
                if self.file_list.size() > 0:
                    self.file_list.select_set(0)
                    self.load_file(None)  # None 表示不是由事件触发
        except Exception as e:
            print(f"加载数据失败: {str(e)}")
            messagebox.showerror("错误", f"加载数据失败: {str(e)}", parent=self.window)

    def load_files_from_group(self, event):
        """从选中的分组加载文件"""
        if not self.group_list.curselection():
            return
            
        self.file_list.delete(0, tk.END)
        group = self.group_list.get(self.group_list.curselection())
        files = self.data_manager.get_files_by_group(group)
        
        for file in files:
            self.file_list.insert(tk.END, file)

    def load_config(self):
        """加载配置"""
        try:
            from configs.set_configs import get_config
            return get_config()
        except Exception as e:
            print(f"加载配置失败: {str(e)}")
            return {}

    def save_window_width(self):
        """保存窗口宽度到配置文件"""
        try:
            # 获取当前窗口宽度
            current_width = self.window.winfo_width()
            
            # 读取当前配置
            from configs.set_configs import get_config
            config = get_config()
            
            # 更新宽度设置
            config['high_freq_window_width'] = current_width
            
            # 保存配置
            import json
            import os
            from configs.configs_data import CONFIG_FILE
            
            os.makedirs(os.path.dirname(CONFIG_FILE), exist_ok=True)
            with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
                json.dump(config, f, indent=4, ensure_ascii=False)
                
        except Exception as e:
            print(f"保存窗口宽度失败: {str(e)}")

    def on_window_resize(self, event):
        """窗口大小改变事件处理"""
        if event.widget == self.window:
            # 延迟保存，避免频繁写入
            self.window.after_cancel(self._save_timer) if hasattr(self, '_save_timer') else None
            self._save_timer = self.window.after(1000, self.save_window_width)

    def _on_closing(self):
        """窗口关闭时的处理"""
        self.__class__._instance = None  # 清除实例引用
        self.window.destroy()

    def __del__(self):
        """析构函数，确保窗口关闭时保存宽度并清除实例引用"""
        self.save_window_width()
        self.__class__._instance = None

    def clear_hotkey_configs(self):
        """清空快捷键配置文件"""
        try:
            config_path = os.path.join(self.config_dir, 'hotkey_configs.json')
            if os.path.exists(config_path):
                os.remove(config_path)
                print("配置文件已清空")
                
            # 清空内存中的配置
            self.hotkey_configs = {}
            
            # 更新UI显示
            for panel in self.config_panels:
                panel.hotkey_entry.delete(0, tk.END)
                panel.result_label.config(text="当前未配置")
                panel.disable()
                
            messagebox.showinfo("成功", "提示词已清空", parent=self.window)
        except Exception as e:
            messagebox.showerror("错误", f"清空提示词失败: {str(e)}", parent=self.window)
